﻿/*
 * @author: wizardc
 */

using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;

namespace DouEditor.Extend
{
    /// <summary>
    /// 更方便使用的场景管理类
    /// </summary>
    public class UnitySceneManager
    {
        private static UnitySceneManager _instance;

        public static UnitySceneManager instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new UnitySceneManager();
                }
                return _instance;
            }
        }

        private Dictionary<string, Scene> _sceneMap = new Dictionary<string, Scene>();
        private Dictionary<string, List<Action<Scene>>> _waitingOpenMap = new Dictionary<string, List<Action<Scene>>>();

        private UnitySceneManager()
        {
            EditorSceneManager.sceneOpened += OnSceneOpened;
        }

        private void OnSceneOpened(Scene scene, OpenSceneMode mode)
        {
            var scenePath = scene.path;
            scenePath = scenePath.ToLower(); // 项目中文件大小写不敏感
            if (_waitingOpenMap.TryGetValue(scenePath, out var list))
            {
                if (!_sceneMap.ContainsKey(scenePath))
                {
                    _sceneMap.Add(scenePath, scene);
                }
                foreach (var listener in list)
                {
                    listener?.Invoke(scene);
                }
                _waitingOpenMap.Remove(scenePath);
            }
        }

        /// <summary>
        /// 打开场景
        /// </summary>
        public void Open(string scenePath, Action<Scene> onOpened, OpenSceneMode mode = OpenSceneMode.Additive)
        {
            scenePath = scenePath.ToLower(); // 项目中文件大小写不敏感
            if (_sceneMap.ContainsKey(scenePath))
            {
                var scene = _sceneMap[scenePath];
                if (scene.isLoaded)
                {
                    onOpened?.Invoke(scene);
                    return;
                }
                _sceneMap.Remove(scenePath);
            }
            for (int i = 0; i < SceneManager.loadedSceneCount; i++)
            {
                var scene = EditorSceneManager.GetSceneAt(i);
                if (scene.path == scenePath)
                {
                    _sceneMap.Add(scenePath, scene);
                    onOpened?.Invoke(scene);
                    return;
                }
            }
            if (!_waitingOpenMap.ContainsKey(scenePath))
            {
                _waitingOpenMap.Add(scenePath, new List<Action<Scene>>());
            }
            var list = _waitingOpenMap[scenePath];
            list.Add(onOpened);
            EditorSceneManager.OpenScene(scenePath, mode);
        }

        /// <summary>
        /// 异步打开场景
        /// </summary>
        public async UniTask<Scene> OpenAsync(string scenePath, OpenSceneMode mode = OpenSceneMode.Additive)
        {
            Scene? scene = null;
            scenePath = scenePath.ToLower(); // 项目中文件大小写不敏感
            Open(scenePath, s => { scene = s; }, mode);
            await UniTask.WaitUntil(() => scene.HasValue);
            return scene.Value;
        }

        /// <summary>
        /// 保存当前场景
        /// </summary>
        public void Save(string scenePath)
        {
            scenePath = scenePath.ToLower(); // 项目中文件大小写不敏感
            if (_sceneMap.ContainsKey(scenePath))
            {
                EditorSceneManager.SaveScene(_sceneMap[scenePath]);
            }
        }

        /// <summary>
        /// 关闭场景
        /// </summary>
        public void Close(string scenePath)
        {
            scenePath = scenePath.ToLower(); // 项目中文件大小写不敏感
            if (_sceneMap.ContainsKey(scenePath))
            {
                EditorSceneManager.CloseScene(_sceneMap[scenePath], true);
                _sceneMap.Remove(scenePath);
                return;
            }
            _waitingOpenMap.Remove(scenePath);
        }
    }
}
